import Generator from 'yeoman-generator'
import glob from 'glob'
import path, { sep } from 'path'
import fs from 'fs'
import prettier from 'prettier'
import { Database, DomainObject, Project, Schemas } from '@/types/domain_models'
import { initProject } from './generate-project'
import { writing as wrtingPom } from './generate-pom'
import { writing as wrtingYaml } from './generate-yaml'
import { writing as writingSringBootStarter } from './generate-springboot-starter'
import { writing as writingModel } from './generate-model'
import { writing as writingMapper } from './generate-mapper'
import { writing as writingService } from './generate-service'
import { writing as writingServiceImpl } from './generate-service-impl'
import { writing as writingController } from './generate-controller'

class TianzhiJavaGenerator extends Generator {
  /**
   * 项目配置
   */
  project: Project

  /**
   * 数据库配置
   */
  database: Database

  /**
   * Schemas
   */
  schemas: Schemas

  constructor(args: string | string[], opts: Generator.GeneratorOptions) {
    super(args, opts)
    this.argument('destination', {
      type: String,
      required: false,
      description: `\n    将项目文件写入到哪里？默认是 domain_model.json 里的项目名称  `,
    })
    this.option('domainJSON', {
      type: String,
      description: `\n    domain_models.json  `,
    })
  }

  async initializing() {
    // 初始化项目配置
    let domainObject: DomainObject = { projeect: {}, schemas: {} } as DomainObject
    const domainJSON = this.options['domainJSON']
    if (domainJSON) {
      try {
        domainObject = JSON.parse(domainJSON)
      } catch (e) {
        this.log(`domain 解析失败, ${e}`)
      }
    }
    const domain = initProject(domainObject)
    this.project = domain.projeect
    this.database = domain.database
    this.schemas = domain.schemas

    // 初始化目标文件夹路径
    const destination = this.options['destination']
    const folderPath = path.resolve(this.destinationPath(), destination || this.project.name)
    this.destinationRoot(folderPath)
  }

  configuring() {}

  writing() {
    // 清空项目
    this._emptyTargetProject()
    // 将最基本的项目文件写入，例如 .gitignore、README.md
    this._copyTpl('project-base')
    // 写入 pom 文件
    wrtingPom(this, this.database, this.project)
    // 写入 yaml 文件
    wrtingYaml(this, this.project.packageName, this.database)
    // 写入 SpringBoot 启动类
    writingSringBootStarter(this, this.project.packageName, this.project.name)
    // 写入 models、mapper、service、controller
    ;[writingModel, writingMapper, writingService, writingServiceImpl, writingController].forEach((writing) =>
      writing(this, this.project.packageName, this.schemas)
    )
  }

  end() {
    // 使用 prettier 格式化代码
    glob.sync('**/*', { cwd: this.destinationPath(), nodir: true }).forEach((file) => {
      const filepath = this.destinationPath(file)
      const content = fs.readFileSync(filepath, 'utf-8')
      const result = prettier.format(content, {
        parser: file.endsWith('java')
          ? 'java'
          : file.endsWith('xml')
          ? 'html'
          : file.endsWith('yml')
          ? 'yaml'
          : 'babel',
        htmlWhitespaceSensitivity: 'ignore',
        plugins: ['prettier-plugin-java'],
      })
      this.log(`格式化${file}...`)
      fs.writeFileSync(filepath, result, 'utf-8')
    })
  }

  _copyTpl(dir: string) {
    glob.sync('**', { cwd: this.templatePath(dir), nodir: true }).forEach((file) => {
      let targetFile = file
      targetFile = targetFile.replace(/^_|\/_/, '.') // 替换 _ ->  .
      targetFile = targetFile.replace(/^\//, '') // 删除尾部斜杠

      const dest = this.destinationPath(targetFile)
      const source = this.templatePath(`${dir}${sep}${file}`)
      this.fs.copy(source, dest)
    })
  }

  _emptyTargetProject() {
    this.fs.delete(this.destinationPath())
  }

  _classFilePath(path: string) {
    return this.destinationPath(
      `src${sep}main${sep}java${sep}${this.project.packageName.replace(/\./g, sep)}${sep}${path}`
    )
  }

  _resourceFilePath(path: string) {
    return this.destinationPath(`src${sep}main${sep}resources${sep}${path}`)
  }
}

export default TianzhiJavaGenerator
